package com.jz.banner.screen.banner.net

import com.alibaba.android.arouter.launcher.ARouter
import com.jz.banner.screen.banner.bean.CheckOutBean
import com.jz.banner.screen.banner.bean.LaunchBean
import com.jz.banner.screen.banner.bean.ResFileBean
import com.jz.banner.screen.banner.bean.isGetDataSuccess
import com.jz.banner.screen.banner.ui.AllowAppActivity
import com.jz.banner.screen.banner.ui.BannerActivity
import com.jz.banner.screen.banner.utils.ConstantUtils
import com.jz.banner.screen.banner.utils.DeviceInfoUtils
import com.jz.banner.screen.bean.BaseBean
import com.jz.banner.screen.bean.database.DBBannerStatistical
import com.jz.banner.screen.bean.database.DBBannerStatisticalDao
import com.jz.banner.screen.listener.MyObserver
import com.jz.banner.screen.ui.App
import com.jz.banner.screen.utils.*
import com.jz.banner.screen.utils.eventbus.Event
import com.jz.banner.screen.utils.eventbus.EventBusUtil
import com.jz.banner.screen.utils.eventbus.EventCode
import com.lzy.okgo.OkGo
import com.lzy.okgo.cache.CacheMode
import com.lzy.okgo.callback.StringCallback
import com.lzy.okgo.model.Response
import io.reactivex.Observable
import io.reactivex.ObservableEmitter
import io.reactivex.ObservableOnSubscribe
import io.reactivex.disposables.Disposable
import java.util.concurrent.TimeUnit


object BannerApi {
    var mBannerGetDisposable: Disposable? = null
    var mBannerStatisticalDisposable: Disposable? = null

    var mMD5CheckOut: String? = null
    var mMD5SubmitInfo: String? = null


    fun initBannerApi() {
        cancelPollingGetBanner()
        initPollingGetBannerRes()
        //TODO：这里还需要初始化 上传 播放报告。
        initPollingUploadBannerStatistical()
    }

    //轮询上传广告信息统计
    private fun initPollingUploadBannerStatistical() {
        cancelPollingUploadBannerStatistical()
        onSwitchUploadBannerStatisticalStatus()
        Observable.create(ObservableOnSubscribe<String> { e ->
            try {
                var list = App.mDaoMaster
                    ?.newSession()
                    ?.queryBuilder(DBBannerStatistical::class.java)
//                    ?.where(WhereCondition.StringCondition(" upload_status=0 GROUP BY launch_id,material_id"))
                    ?.where(DBBannerStatisticalDao.Properties.Upload_status.eq(0))//上传状态。//0:未上传，1:上传成功,2:上传失败
                    ?.offset(0)
                    ?.limit(BannerActivity.mSettingInfo?.polling_statistics_items ?: 500)
                    ?.orderDesc(DBBannerStatisticalDao.Properties.LocalOrderId)
                    ?.list()//每次上传10条
                d("initPollingUploadBannerStatistical=>list.size:${list?.size}")
                var newList = list?.groupBy { it.device_id + "**" + it.launch_id + "**" + it.material_id + "**" + it.getPlay_start_date().split(" ").first() }
                var posList = newList?.map { entry ->
                    val split = entry.key.split("**")
                    val device_id = split[0]
                    val launch_id = split[1]
                    val material_id = split[2]
                    val play_start_date = split[3]
                    val statisticalList = entry.value
                    HashMap<String, Any>().apply {
                        this["launch_id"] = launch_id
                        this["material_id"] = material_id
                        this["device_id"] = device_id
                        this["play_time"] = statisticalList.map { it.play_time }.reduce { acc, play_time -> acc + play_time }
                        this["play_num"] = statisticalList.map { it.play_num }.reduce { acc, play_num -> acc + play_num }
                        this["play_launch_num"] = statisticalList.map { it.play_launch_num }.reduce { acc, play_launch_num -> acc + play_launch_num }
                        this["play_start_date"] = play_start_date
                    }
                }
//                XLog.d("initPollingUploadBannerStatistical=>newList:${CommUtils.gson.toJson(newList)}")
//                XLog.d("initPollingUploadBannerStatistical=>posList:${CommUtils.gson.toJson(posList)}")
                //XLog.json(CommUtils.gson.toJson(newList))

                if (list != null && list.isNotEmpty()) {
                    val toJson = CommUtils.gson.toJson(posList)
                    //d("params_data:${toJson}")
                    GetApi.getData(sortedMapOf(ConstantUtils.params_data to toJson), GetApi.launchCensus)
                        .compose(RxUtils.io())
                        .subscribe(object : MyObserver<BaseBean<CheckOutBean>>() {
                            override fun onError(t: Throwable) {
                                list.forEach {
                                    val i = it?.upload_failed_times ?: 0
                                    it?.upload_failed_times = i + 1
                                    it.upload_status = 2
                                }
                                App.mDaoSession?.dbBannerStatisticalDao?.updateInTx(list)
                                d("initPollingUploadBannerStatistical=>onError:${t}")
                                e.onComplete()
                            }

                            override fun onNext(t: BaseBean<CheckOutBean>) {
                                list.forEach { it.upload_status = 1 }
                                App.mDaoSession?.dbBannerStatisticalDao?.updateInTx(list)
                                d("initPollingUploadBannerStatistical=>dataIsNull:$toJson")
                                e.onComplete()
                            }

                        })
                } else {
                    e.onComplete()
                }
            } catch (t: Exception) {
                d("initPollingUploadBannerStatistical->$t")
                e.onComplete()
            }
        })
            .repeatWhen { return@repeatWhen it.flatMap { return@flatMap Observable.timer(BannerActivity.mSettingInfo?.polling_statistics_time ?: 5L, TimeUnit.SECONDS) } }
            .subscribe(object : MyObserver<String>() {
                override fun onSubscribe(d: Disposable) {
                    super.onSubscribe(d)
                    mBannerStatisticalDisposable = d
                }

                override fun onError(e: Throwable) {
                    d("pollingOrderList=>:onError:$e")
                }

                override fun onNext(t: String) {
                    d("pollingOrderList=>:onNext:$t")
                }
            })
    }

    //切换 上传失败的广告信息统计
    fun onSwitchUploadBannerStatisticalStatus() {
        //在线程操作
        Observable.create(ObservableOnSubscribe<Int> { e ->
            try {
                //把已经上传的订单删除掉
                var hadUploadList = App.mDaoSession?.queryBuilder(DBBannerStatistical::class.java)
                    ?.where(DBBannerStatisticalDao.Properties.Upload_status.eq(1))   //上传状态。0:未上传，1:上传成功,2:上传失败
                    ?.list()
                if (hadUploadList?.isNotEmpty() == true) App.mDaoSession?.dbBannerStatisticalDao?.deleteInTx(hadUploadList)
                //把已经上传的失败的订单次数超过7次
                var hadUploadFailed7TimesList = App.mDaoSession?.queryBuilder(DBBannerStatistical::class.java)
                    //TODO:这里应该新增后台控制上传失败次数。
                    ?.where(DBBannerStatisticalDao.Properties.Upload_failed_times.gt(BannerActivity.mSettingInfo?.upload_failed_times ?: 4))   //上传状态。0:未上传，1:上传成功,2:上传失败
                    ?.list()
                if (hadUploadFailed7TimesList?.isNotEmpty() == true) App.mDaoSession?.dbBannerStatisticalDao?.deleteInTx(hadUploadFailed7TimesList)

                //把上传“失败” 转成 “未上传”，然后触发重新上传。
                var hadUploadFailedList = App.mDaoSession?.queryBuilder(DBBannerStatistical::class.java)
                    ?.where(DBBannerStatisticalDao.Properties.Upload_status.eq(2))   //上传状态。0:未上传，1:上传成功,2:上传失败
                    ?.list()?.apply { forEach { it.upload_status = 0 } }
                if (hadUploadFailedList?.isNotEmpty() == true) App.mDaoSession?.dbBannerStatisticalDao?.updateInTx(hadUploadFailedList)
                d("hadUploadFailedList:${hadUploadFailedList?.size},hadUploadList:${hadUploadList?.size},hadUploadFailed7TimesList:${hadUploadFailed7TimesList?.size},")
                e.onNext(0)
                e.onComplete()
            } catch (ex: Exception) {
                e.onError(ex)
            }
        })
            .compose(RxUtils.io())
            .subscribe(object : MyObserver<Int>() {
                override fun onNext(t: Int) {
                    d("转换成功!")
                }

                override fun onError(e: Throwable) {
                    d(e.message.toString())
                }
            })
    }

    //取消 轮询 上传广告信息统计
    fun cancelPollingUploadBannerStatistical() {
        try {
            mBannerStatisticalDisposable?.dispose()
            mBannerStatisticalDisposable = null
        } catch (e: Exception) {
            //ToastUtil.showToast("自动上传失败:$e")
        }
    }


    var mCheckUpgradeCount = 1L

    //轮询获取广告信息资源以及心跳、授权、更新apk
    private fun initPollingGetBannerRes() {
        Observable.create(ObservableOnSubscribe<String> { e ->
            OkGo.post<String>(GetApi.checkout) //
                .params(ConstantUtils.getParams(sortedMapOf(ConstantUtils.c_md5 to DeviceInfoUtils.mMd5DeviceInfo)))
                .cacheKey(GetApi.checkout)
                .cacheMode(CacheMode.REQUEST_FAILED_READ_CACHE)
                .execute(object : StringCallback() {

                    override fun onSuccess(response: Response<String>?) {
                        //d("checkout_json->${response?.body()}")
                        var checkOutBean = try {
                            CommUtils.gson.fromJson(response?.body(), CheckOutBean::class.java) as CheckOutBean
                        } catch (e: Exception) {
                            CheckOutBean().apply { message = e.toString() }
                        }
                        when {
                            checkOutBean.code == 406 -> go2AllowActivity(e)
                            checkOutBean.isGetDataSuccess() -> {
                                if (AllowAppActivity.mIsShowAllow) EventBusUtil.sendEvent(Event(EventCode.FINISH_ALLOW_SCREEN))
                                val checkOutData = checkOutBean.data
                                if (checkOutData != null) {
                                    //更新设备信息到服务端
                                    if (checkOutData.c_update == 1) postDeviceInfo()

                                    //TODO: md5不一样，则检查更新
                                    if (checkOutData.s_md5 != mMD5CheckOut) {
                                        //获取更新数据接口
                                        OkGo.post<String>(GetApi.getLaunch) //
                                            .params(ConstantUtils.getParams(sortedMapOf()))
                                            .cacheKey(GetApi.getLaunch)
                                            .cacheMode(CacheMode.REQUEST_FAILED_READ_CACHE)
                                            .execute(object : StringCallback() {

                                                override fun onSuccess(response: Response<String>?) {
                                                    d("getLaunch_json->${response?.body()}")
                                                    var launchBean = try {
                                                        CommUtils.gson.fromJson(response?.body(), LaunchBean::class.java) as LaunchBean
                                                    } catch (e: Exception) {
                                                        LaunchBean().apply { message = e.toString() }
                                                    }
                                                    if (launchBean.isGetDataSuccess()) {
                                                        val launchBeanData = launchBean.data
                                                        //TODO:保存mMD5CheckOut
                                                        mMD5CheckOut = checkOutData.s_md5
                                                        SPUtils.putString(ConstantUtils.mMD5CheckOut, mMD5CheckOut)
                                                        if (launchBeanData != null) {
                                                            d("launchBeanData::${CommUtils.gson.toJson(launchBeanData)}")
                                                            try {
                                                                //TODO：处理广告参数数据
                                                                BannerActivity.T1 = launchBeanData.banner_params?.T1 ?: 5
                                                                BannerActivity.T2 = launchBeanData.banner_params?.T2 ?: 5
                                                                BannerActivity.T3 = launchBeanData.banner_params?.T3 ?: 60
                                                                BannerActivity.T4 = launchBeanData.banner_params?.T4 ?: 3

                                                                //TODO：处理广告资源数据
                                                                BannerActivity.mBannerImageList.clear()
                                                                BannerActivity.mBannerVideoList.clear()
                                                                launchBeanData.res_info?.forEach { resInfo ->
                                                                    resInfo.launch_material?.forEach { launchMaterial ->
                                                                        var resFileBean = ResFileBean().apply {
                                                                            this.launch_id = resInfo.launch_id
                                                                            this.device_id = resInfo.device_id
                                                                            this.device_code = resInfo.device_code
                                                                            this.customer_id = resInfo.customer_id
                                                                            this.org_id = resInfo.org_id
                                                                            this.material_id = launchMaterial.material_id
                                                                            this.mat_name = launchMaterial.mat_name
                                                                            this.mat_type = launchMaterial.mat_type
                                                                            this.file_url = launchMaterial.file_url
                                                                            this.cover_url = launchMaterial.cover_url
                                                                            this.file_type = launchMaterial.file_type
                                                                            this.is_last = launchMaterial.is_last
                                                                            this.display_type = launchBeanData.banner_params?.display_type ?: 0
                                                                            this.scale_type = launchBeanData.banner_params?.scale_type ?: 0
                                                                        }
                                                                        if (resFileBean.file_url != null || resFileBean.file_url!!.isNotBlank()) {
                                                                            //此处过滤后台返回空链接。
                                                                            when (launchMaterial.file_type) {
                                                                                //图片
                                                                                1 -> BannerActivity.mBannerImageList.add(resFileBean)
                                                                                //视频
                                                                                2 -> BannerActivity.mBannerVideoList.add(resFileBean)
                                                                            }
                                                                        }
                                                                    }
                                                                }

                                                                //TODO:配置信息
                                                                BannerActivity.mSettingInfo = launchBeanData.setting_info

                                                                //TODO：处理更新APP
                                                                val upgradeInfo = launchBeanData.upgrade_info
                                                                d("getAppVersionCode:${ConstantUtils.getAppVersionCode()},upgradeInfo?.version_code:${upgradeInfo?.version_code}")
                                                                val versionCode = upgradeInfo?.version_code ?: 0
                                                                if (ConstantUtils.getAppVersionCode() < versionCode) {
                                                                    //ConstantUtils.checkUpdateApp()
                                                                    //一句代码，傻瓜式更新
                                                                    upgradeInfo?.url?.let { ConstantUtils.appUpdate(versionCode, it) }
                                                                }
                                                                SPUtils.putInt(ConstantUtils.version_code, upgradeInfo?.version_code ?: 0)
                                                                SPUtils.putString(ConstantUtils.upgrade_url, upgradeInfo?.url)

                                                                //TODO:重启广告屏
                                                                EventBusUtil.sendEvent(Event(EventCode.FINISH_BANNER_SCREEN))
                                                            } catch (e: Exception) {
                                                            }
                                                            e.onComplete()
                                                        } else {
                                                            //这里有可能存在删除广告，为空需要处理操作。
                                                            BannerActivity.mBannerImageList.clear()
                                                            BannerActivity.mBannerVideoList.clear()
                                                            e.onComplete()
                                                        }
                                                    } else {
                                                        e.onComplete()
                                                    }
                                                }

                                                override fun onCacheSuccess(response: Response<String>?) {
                                                    onSuccess(response)
                                                }

                                                override fun onError(response: Response<String>?) {
                                                    super.onError(response)
                                                    e.onComplete()
                                                }
                                            })

                                    } else {
                                        //md5一样，不需要更新
                                        e.onComplete()
                                    }

                                    if (mMD5CheckOut == null) mMD5CheckOut = SPUtils.getString(ConstantUtils.mMD5CheckOut)
                                } else {
                                    e.onComplete()
                                }
                            }
                            else -> e.onComplete()
                        }
                    }

                    override fun onCacheSuccess(response: Response<String>?) {
                        onSuccess(response)
                    }
                })
            if (mMD5SubmitInfo != DeviceInfoUtils.mMd5DeviceInfo) postDeviceInfo()

            try {
                //这里的操作是保证有存在更新，每10 * polling_get_banner_res_time 秒再检查一下更新。
                if (mCheckUpgradeCount % 10 == 0L) {
                    val versionCode = SPUtils.getInt(ConstantUtils.version_code, 0)
                    if (ConstantUtils.getAppVersionCode() < versionCode) {
                        val upgradeUrl = SPUtils.getString(ConstantUtils.upgrade_url)
                        upgradeUrl?.let { ConstantUtils.appUpdate(versionCode, it) }
                    }
                }
            } catch (e: Exception) {

            }
            mCheckUpgradeCount++
        })
            .repeatWhen {
                return@repeatWhen it.flatMap {
                    return@flatMap Observable.timer(BannerActivity.mSettingInfo?.polling_get_banner_res_time ?: 5L, TimeUnit.SECONDS)
                }
            }
            .subscribe(object : MyObserver<String>() {
                override fun onSubscribe(d: Disposable) {
                    super.onSubscribe(d)
                    mBannerGetDisposable = d
                }

                override fun onError(e: Throwable) {
                    d("initBannerApi->pollingGetBannerRes->onError->$e")
                }

                override fun onNext(t: String) {
                }
            })
    }

    //跳转授权界面
    private fun go2AllowActivity(e: ObservableEmitter<String>) {
        if (!AllowAppActivity.mIsShowAllow) {
            ARouter.getInstance()
                .build(ARouterUtils.AllowAppActivity)
                .navigation()
            ActivityCollector.finishAll()
        }
        e.onComplete()
    }

    private fun postDeviceInfo() {
        GetApi.getData(sortedMapOf(ConstantUtils.params_data to DeviceInfoUtils.mDeviceInfoJson), GetApi.submitInfo)
            .compose(RxUtils.io())
            .subscribe(object : MyObserver<BaseBean<CheckOutBean>>() {
                override fun onNext(t: BaseBean<CheckOutBean>) {
                    //TODO:更改md5
                    mMD5SubmitInfo = DeviceInfoUtils.mMd5DeviceInfo
                }
            })
    }

    //取消 轮询 获取广告信息资源
    fun cancelPollingGetBanner() {
        try {
            mBannerGetDisposable?.dispose()
            mBannerGetDisposable = null
        } catch (e: Exception) {
            d("initBannerApi->cancelPollingBanner->$e")
        }
    }


    private fun d(msg: String) {
        CommUtils.println("BannerApi->", msg)
    }

}